package com.linkallcloud.web.filter;

import java.io.IOException;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.linkallcloud.core.dto.Result;
import com.linkallcloud.core.exception.Exceptions;
import com.linkallcloud.core.lang.Mirror;
import com.linkallcloud.core.lang.Strings;
import com.linkallcloud.core.www.ISimpleUser;
import com.linkallcloud.core.www.ITokenBox;
import com.linkallcloud.core.www.utils.WebUtils;
import com.linkallcloud.web.utils.Controllers;

public abstract class CommonLoginFilter<U extends ISimpleUser> extends LacCommonFilter {

    protected Mirror<U> mirror;
    protected ITokenBox tokenBox;

    @SuppressWarnings("unchecked")
    public CommonLoginFilter(ITokenBox tokenBox) {
        super();
        try {
            mirror = Mirror.me((Class<U>) Mirror.getTypeParams(getClass())[0]);
        } catch (Throwable e) {
            if (log.isWarnEnabled()) {
                log.warn("!!!Fail to get TypeParams for self!", e);
            }
        }
        this.tokenBox = tokenBox;
    }

    @SuppressWarnings("unchecked")
    public CommonLoginFilter(ITokenBox tokenBox, List<String> ignoreRes, boolean override) {
        super(ignoreRes, override);
        try {
            mirror = Mirror.me((Class<U>) Mirror.getTypeParams(getClass())[0]);
        } catch (Throwable e) {
            if (log.isWarnEnabled()) {
                log.warn("!!!Fail to get TypeParams for self!", e);
            }
        }
        this.tokenBox = tokenBox;
    }

    public Class<U> getSessionUserClass() {
        return (null == mirror) ? null : mirror.getType();
    }

    protected abstract String getAppCode();

    protected abstract String getLoginUrl();

    @Override
    protected void doConcreteFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        ISimpleUser u = getLoginUser(getAppCode(), request);
        if (null == u) { // suser为空，表示初次登陆或者本地session超时
            if (isIndexOrLocalLoginRequest(request)) {// 不是SSO认证，且是访问首页(登陆页面)
                chain.doFilter(request, response);
                return;
            } else {
                toLogin(getLoginUrl(), request, response);
                return;
            }
        }

        chain.doFilter(request, response);
    }

    /**
     * 是否系统首页或者是本地登录的请求，用于非SSO认证过滤时的判断
     *
     * @param request
     * @return boolean
     */
    protected boolean isIndexOrLocalLoginRequest(HttpServletRequest request) {
        String sp = request.getServletPath();
        if (sp.indexOf("/index.html") != -1 || sp.indexOf("/login") != -1) {
            return true;
        }
        return false;
    }

    /**
     * 取出登录用户
     *
     * @param appCode
     * @param request
     * @return
     */
    protected ISimpleUser getLoginUser(String appCode, HttpServletRequest request) {
        return (ISimpleUser) Controllers.getAppSessionUser(appCode, request, tokenBox, getSessionUserClass());
    }

    /**
     * @param loginUrl
     * @param request
     * @param hResponse
     * @throws IOException
     */
    protected void toLogin(String loginUrl, HttpServletRequest request, HttpServletResponse hResponse)
            throws IOException {
        if (!Strings.isBlank(loginUrl) && !loginUrl.startsWith("http")
                && !loginUrl.startsWith(request.getContextPath())) {
            loginUrl = request.getContextPath() + loginUrl;
        }
        if (WebUtils.isAjax(request)) {
            hResponse.setCharacterEncoding("UTF-8");
            Result<Object> result = Exceptions.makeErrorResult(Exceptions.CODE_ERROR_SESSION_TIMEOUT, "会话超时");
            result.setData(loginUrl);
            // response.sendError(HttpStatus.UNAUTHORIZED.value(), "您已经太长时间没有操作,请刷新页面");
            WebUtils.out(hResponse, result);
        } else {
            hResponse.sendRedirect(loginUrl);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}
